package com.free4k.keepalive.netty.hander;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.free4k.keepalive.bean.AccessBackDTO;
import com.free4k.keepalive.bean.HeartBackDTO;
import com.free4k.keepalive.bean.HeartRequestDTO;
import com.free4k.keepalive.constant.LapiUriConstat;
import com.free4k.keepalive.manager.DeviceChannelContext;
import com.free4k.keepalive.manager.HttpKeepAliveManager;
import com.free4k.keepalive.manager.RequestDeviceManager;
import com.free4k.keepalive.manager.ResponseDeviceManager;
import com.free4k.keepalive.netty.factory.ChannelFactory;
import com.free4k.keepalive.netty.factory.HttpResponseFactory;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.util.CharsetUtil;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;


/**
 * Copyright (C),  2018-2025, ZheJiang Uniview Technologies Co., Ltd. All rights reserved.
 * <http://www.uniview.com/>
 * <p>
 * FileName : HttpHeartHandler
 *
 * @Author : s04180
 * Date     : 2019/12/30 17:04
 * DESCRIPTION:
 * <p>
 * History:
 * DATE        NAME        DESC
 */

public class LapiServerHandler2 extends SimpleChannelInboundHandler {

    /**
     * 日志信息
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(LapiServerHandler.class);

    /**
     * 设备序列号
     */
    public volatile String serialNo;

    private static CloseableHttpClient client = HttpClients.createDefault();


    private ReAlarmRecordServiceImpl reAlarmRecordService = SpringUtils.getBean(ReAlarmRecordServiceImpl.class);

    private RedisService redisService = SpringUtils.getBean(RedisService.class);

    private RePersonInfoServiceImpl rePersonInfoService = SpringUtils.getBean(RePersonInfoServiceImpl.class);


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        try {
            if (msg instanceof FullHttpRequest) {
                FullHttpRequest httpRequest = (FullHttpRequest) msg;
                String requestUri = httpRequest.uri();
                String content = httpRequest.content().toString(CharsetUtil.UTF_8);
                if (requestUri.contains(LapiUriConstat.HEART_URI)) {
                    saveDeviceCtx(content, ctx);
                    heartResponse(ctx);

                    //更新为在线
                    updateInLine();

                } else if (httpRequest.uri().contains(LapiUriConstat.ACCESS_RECEIVE_URI)) {
                    String accessRecord = httpRequest.content().toString(CharsetUtil.UTF_8);
                    JSONObject jsonObject = JSON.parseObject(accessRecord);
                    Long seq = jsonObject.getLong("Seq");
                    Long uploadTime = jsonObject.getLong("Timestamp") * 1000;
                    int notificationType = jsonObject.getInteger("NotificationType");
                    long passTime = jsonObject.getJSONArray("FaceInfoList").getJSONObject(0).getLong("Timestamp") * 1000;
                    accessResponse(ctx, seq, 0);

                    //处理人脸识别结果
                    showInfoAndOpenDoor(jsonObject, passTime);

                    LOGGER.debug("Access Record Seq:{},UploadTime:{},,PassTime:{},NotificationType:{}", seq, DateFormatUtils.format(uploadTime, "yyyy-MM-dd HH:mm:ss"),
                            DateFormatUtils.format(passTime, "yyyy-MM-dd HH:mm:ss"), notificationType);
                } else {
                    ctx.fireChannelRead(msg);
                }
            } else if (msg instanceof FullHttpResponse) {
                FullHttpResponse response = (FullHttpResponse) msg;
                HttpResponseFactory.responseHandle(ctx, response);
            } else {
                ctx.fireChannelRead(msg);
            }
        } catch (Exception e) {
            LOGGER.error("Read [{}] channel msg[{}] failed for:{}", ctx.channel().remoteAddress().toString()
                    , JSON.toJSONString(msg), e.getMessage(), e);
        }
    }

    /**
     * 更新设备在线信息
     */
    private  void updateInLine(){
        //更新本设备
        ReMachine machine = new ReMachine();
        machine.setOnlineStatus("1");
        machine.setCode(this.serialNo);
        reMachineService.updateReMachineByMac(machine);
    }
    private  void updateOffLine(){
        ReMachine reMachine = new ReMachine();
        reMachine.setOnlineStatus("0");
        reMachine.setCode(this.serialNo);
        reMachineService.updateReMachineByMac(reMachine);
    }



    /**
     * 处理人脸识别结果
     */
//    @Transactional
    void showInfoAndOpenDoor(JSONObject jsonObject, Long passTime) {

        //返回设备的数据
        Map<String,String> map = new HashMap<>();

        //体温
        String temperature = jsonObject.getJSONArray("FaceInfoList").getJSONObject(0).getString("Temperature");
        //ID号码
        String identityNo = jsonObject.getJSONArray("LibMatInfoList").getJSONObject(0).getJSONObject("MatchPersonInfo").getString("IdentityNo");

        //设备显示信息
        String resultMsg = "";

        //可以查询到信息,对应的处理
        try {

            PersonInfo personInfo = rePersonInfoService.selectById(identityNo);

            map.put("name", personInfo.getName());
            map.put("state",personInfo.getState());
            map.put("resultCode","0");

            double terature = Double.parseDouble(temperature);

            String cachemaxC = redisService.getCacheObject("sys_config:in.maxC");
            String cacheminC = redisService.getCacheObject("sys_config:in.minC");
            if (cacheminC == null) {
                cacheminC = "35.5";
            }
            if (cachemaxC == null) {
                cachemaxC = "37.2";
            }

            double maxC = Double.parseDouble(cachemaxC);
            double minC = Double.parseDouble(cacheminC);

            if (terature != 0.0 && terature > maxC){
                resultMsg = "体温高于" + maxC +"度";
//                reAlarmRecordService.insertReAlarmRecord(reAlarmRecord);

            }else if (terature != 0.0 && terature < minC){
                resultMsg = "体温低于" + minC +"度";
//                reAlarmRecordService.insertReAlarmRecord(reAlarmRecord);
            }else{

                if (state.equals("1")){

                    int i = Integer.parseInt(nucleicAcidDay);

                    String cacheDay = redisService.getCacheObject("sys_config:in.out.day");
                    if (cacheDay == null){
                        cacheDay = "7";
                    }

                    int day = Integer.parseInt(cacheDay);

                    if (i <= day){
                        map.put("resultCode","1");
                        resultMsg = "";
                    }else{

                        resultMsg = "有效期超过" + day + "天";
                        map.put("state","0");
//                        reAlarmRecordService.insertReAlarmRecord(reAlarmRecord);
                    }

                }else if(state.equals("2")){
                    map.put("state","2");
//                    reAlarmRecordService.insertReAlarmRecord(reAlarmRecord);
                }else if(state.equals("3")){
                    map.put("state","3");
//                    reAlarmRecordService.insertReAlarmRecord(reAlarmRecord);
                }
            }

            map.put("resultMsg",resultMsg);
            showInfo(passTime,map);

        } catch (Exception e) {

        }

    }

    /**
     * 单独进行开门的方法
     */
    private void openDoor() {

        FullHttpRequest httpRequest = null;
        try {
            httpRequest = RequestDeviceManager.createRequestDeviceInfo(LapiUriConstat.OPEN_DOOR, "", HttpMethod.PUT);
            Map<String, String> respMap = HttpKeepAliveManager.getResponseMapByKeepAliveConnection(this.serialNo, httpRequest);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 显示播报同时控制开门
     * @param passTime
     * @param showMap 显示的信息
     */

    //根据需求，自定义传入参数类型
    private void showInfo(Long passTime, Map<String,String> showMap) {

        FullHttpRequest httpRequest = null;

        Map<Object, Object> map = new HashMap<>();

        //根据自己的逻辑组装数据

        String str = JSON.toJSONString(map);

        try {
            httpRequest = RequestDeviceManager.createRequestDeviceInfo(LapiUriConstat.SHOW_INFO, str, HttpMethod.PUT);
            Map<String, String> respMap = HttpKeepAliveManager.getResponseMapByKeepAliveConnection(serialNo, httpRequest);
            if (Objects.nonNull(respMap)) {
                LOGGER.info("Device:{} Response Info:\n{}", serialNo, JSON.toJSONString(map, SerializerFeature.PrettyFormat));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 心跳回包拼装
     *
     * @return
     * @throws Exception
     */
    private void heartResponse(ChannelHandlerContext ctx) {
        HeartBackDTO heartBackDO = new HeartBackDTO(LapiUriConstat.HEART_URI, 0, new Date());
        ResponseDeviceManager.responseDevice(ctx, heartBackDO);
        //LOGGER.info("[SERIAL_NO][{}] 心跳回包正常！客户端IP: {}", serialNo, ctx.channel().remoteAddress());
    }

    /**
     * 响应终端
     * StatusCode：0：平台接收成功，1：平台接收失败
     * StatusString：Succeed/Common Fail
     * RecordID：通行记录ID（对应过人记录里的"Seq"字段）
     *
     * @param ctx
     * @param seq        记录id
     * @param statusCode 0-成功 1-失败
     */
    public void accessResponse(ChannelHandlerContext ctx, Long seq, Integer statusCode) {
        AccessBackDTO accessRecordBack = new AccessBackDTO(LapiUriConstat.ACCESS_RESPONSE_URI, statusCode, seq);
        ResponseDeviceManager.responseDevice(ctx, accessRecordBack);
    }


    /**
     * 保存链接
     *
     * @param strRequest
     * @param ctx
     * @throws Exception
     */
    private void saveDeviceCtx(String strRequest, ChannelHandlerContext ctx) {
        HeartRequestDTO request = JSONObject.parseObject(strRequest, HeartRequestDTO.class);
        String serialNo = request.getStrDeviceCode();
        this.serialNo = serialNo;
        DeviceChannelContext deviceCtx = ChannelFactory.getChannelBySerialNo(serialNo);
        if (Objects.isNull(deviceCtx)) {
            //添加设备的链接通道
            ChannelFactory.addChannel(serialNo, ctx);
        } else {
            // 刷新设备对应的链接通道
            ChannelFactory.freshChannel(serialNo, ctx);
        }
    }

    /**
     * 添加channel时
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
        Channel incoming = ctx.channel();
        LOGGER.debug("SimpleChatClient:" + incoming.remoteAddress() + "通道被添加");
    }

    /**
     * 删除channel时
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) {
        Channel channel = ctx.channel();
        LOGGER.debug("SimpleChatClient:{},通道被删除", channel.remoteAddress());
    }

    /**
     * 服务端监听到客户端不活动
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        //服务端接收到客户端掉线通知
        Channel incoming = ctx.channel();
        updateOffLine();
        LOGGER.error("SimpleChatClient: {}  掉线", incoming.remoteAddress());
    }

    /**
     * 服务端监听到客户端活动
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        //服务端接收到客户端上线通知
        Channel incoming = ctx.channel();
        LOGGER.debug("SimpleChatClient:" + incoming.remoteAddress() + "上线");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        Channel channel = ctx.channel();
        LOGGER.error("SimpleChatClient:{},异常断开,{}", channel.remoteAddress(), cause);
        //出现异常判断下通道是否还可用
        if (!channel.isWritable()) {
            ctx.close();
            HttpResponseFactory.removeResponse(ctx);
        }
    }
}
